<?php
Raise::load('core.RaiseExceptionHandler');
Raise::load('core.RaiseApplication');
Raise::load('core.RaiseLog');
Raise::load('core.RaiseDefaultExceptionPage');
Raise::load('core.RaiseDateTime');
Raise::load('core.RaisePath');
Raise::load('core.RaiseAccessReset');

/**
 * RaisePostbackExceptionHandler class
 * A handler that handles postback errors
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Exception
 * @since 1.2
 */
class RaiseDefaultExceptionHandler extends RaiseExceptionHandler {

    /**
     * The RaiseApplication that created this handler
     * @var RaiseApplication
     */
    protected $application;

    /**
     * The log file to log to
     * @var RaiseLog
     */
    protected $log;

    /**
     * Create a new RaiseExceptionHandler
     * @param RaiseApplication $app The application that is creating this handler
     */
    public function __construct($app) {
        $this->application = $app;
        set_error_handler(array($this, 'errorHandler'), ~E_ALL);
        set_exception_handler(array($this, 'exceptionHandler'));
        $file = $this->application->settings()->get('ErrorHandling', 'logFile');
        if ($file) {
            $t = array(
                '$app.name$' => $this->application->name(),
                '$date$' => RaiseDateTime::now()->toFormat('dMY')
            );
            $file = str_replace(array_keys($t), $t, $file);
            $file = RaisePath::combine(RaisePath::combine(RaisePath::phpRaisePath(), 'log'), $file);
            $this->log = new RaiseLog($file, $this->application->settings()->get('ErrorHandling', 'logMaxSize'));
        }
    }

    /**
     * Get or set the RaiseApplication that created this handler
     * @param RaiseApplication $app (optional) If set, the new value will be set.
     * @return RaiseApplication
     */
    public function application($app = null) {
        if (func_num_args() == 1) {
            if (!($app instanceof RaiseApplication)) {
                throw new RaiseInvalidArgumentException('RaiseExceptionHandler::application() expecting $app to be an instance of RaiseApplication, ' . RaiseVariable::typeInfo($app) . ' given instead.');
            }
            $this->application = $app;
        }
        return $this->application;
    }

    /**
     * The error handler that will handle all PHP errors
     * @ignore
     */
    public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
        $e = new RaiseException();
        $e->setCode($errno);
        $e->setLine($errline);
        $e->setMessage($errstr);
        $e->setFile($errfile);
        $e->setContext($errcontext);
        self::exceptionHandler($e);
    }

    /**
     * Handles all exception thrown in the application that are not handled
     * @param Exception $ex The exception caught
     */
    public function exceptionHandler($ex) {
        if ($ex === $this->lastHandledException) {
            var_dump($ex);
            die("Recursive Error Handling Occurred.");
        }
        $page = $this->application->settings()->get('ErrorHandling', 'errorPage');
        if (!$page) {
            $page = 'RaiseDefaultExceptionPage';
        }

        if ($this->log) {
            // if log is enabled, write to log as well
            $this->log->write($ex);
        }

        $this->lastHandledException = $ex;

        $o = new $page($ex);

        $this->application->accessControl(new RaiseAccessReset());
        $this->application->startPage($o);
    }

}